import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

/**
 * @author IBRAHIMLI NIhat
 * @author BAYRAMOV Matin
 * 
 */
public class Task implements Comparable<Task> {

	public static int all_task_number = 1;

	private int id;

	private String name;

	private int type;

	private boolean scheduled;

	private int topLevel;

	private int bottomLevel;

	private int executionTime;

	Map<Task, Integer> successor;

	Map<Task, Integer> predecessor;

	public Task(int executionTime) {
		setId(Task.all_task_number);
		Task.all_task_number++;
		this.setExecutionTime(executionTime);
		this.setType(0);
		this.setTopLevel(0);
		this.setBottomLevel(executionTime);
		this.setScheduled(false);
		this.successor = new HashMap<Task, Integer>();
		this.predecessor = new HashMap<Task, Integer>();
	}

	/**
	 * Create a task randomly and return it;
	 * 
	 * @param maxNumber
	 * @return
	 */
	public static Task getTask(int maxNumber) {
		int executionTime = 1 + (int) (Math.random() * (maxNumber - 1));
		Task task = new Task(executionTime);
		return task;
	}

	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	/**
	 * @param name
	 *            the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * @return the executionTime
	 */
	public int getExecutionTime() {
		return executionTime;
	}

	/**
	 * @param executionTime
	 *            the executionTime to set
	 */
	public void setExecutionTime(int executionTime) {
		this.executionTime = executionTime;
	}

	/**
	 * 
	 */
	public String toString() {
		// String str = "[ t";
		// str += this.getId() + ", ";
		// str += this.getExecutionTime();
		// str += " ]";

		String str = "t" + this.getId();
		return str;
	}

	/**
	 * @return the id
	 */
	public int getId() {
		return id;
	}

	/**
	 * 
	 * @return the successor
	 */
	public Map<Task, Integer> getSuccessor() {
		return successor;
	}

	/**
	 * 
	 * @param successor
	 */
	public void setSuccessor(Map<Task, Integer> successor) {
		this.successor = successor;
	}

	/**
	 * 
	 * @return the predecessor
	 */
	public Map<Task, Integer> getPredecessor() {
		return predecessor;
	}

	/**
	 * 
	 * @param predecessor
	 */
	public void setPredecessor(Map<Task, Integer> predecessor) {
		this.predecessor = predecessor;
	}

	/**
	 * @param weight
	 * @param task
	 * 
	 */
	public void addSuccessor(Task task, int weight) {
		this.successor.put(task, weight);
	}

	/**
	 * 
	 * @param weight
	 * @param task
	 */
	public void addPredecessor(Task task, int weight) {
		this.predecessor.put(task, weight);
	}

	/**
	 * @param id
	 *            the id to set
	 */
	public void setId(int id) {
		this.id = id;
	}

	/**
	 * @return the type
	 */
	public int getType() {
		return type;
	}

	/**
	 * @param type
	 *            the type to set
	 */
	public void setType(int type) {
		this.type = type;
	}

	/**
	 * @return the topLevel
	 */
	public int getTopLevel() {
		if (this.getType() == 1) {
			return 0;
		}
		return this.topLevel;
	}

	/**
	 * @param topLevel
	 *            the topLevel to set
	 */
	public void setTopLevel(int topLevel) {
		this.topLevel = topLevel;
	}

	/**
	 * @return the bottomLevel
	 */
	public int getBottomLevel() {
		if (this.getType() == 0) {
			return this.getExecutionTime();
		}
		return this.bottomLevel;
	}

	/**
	 * @param bottomLevel
	 *            the bottomLevel to set
	 */
	public void setBottomLevel(int bottomLevel) {
		this.bottomLevel = bottomLevel;
	}

	/**
	 * @return the scheduled
	 */
	public boolean isScheduled() {
		return scheduled;
	}

	/**
	 * @param scheduled
	 *            the scheduled to set
	 */
	public void setScheduled(boolean scheduled) {
		this.scheduled = scheduled;
	}

	/**
	 * Get makespan for a task
	 * 
	 * @return
	 */
	public int getPriority() {
		return this.getBottomLevel() + this.getTopLevel();
	}

	@Override
	public int compareTo(Task o) {

		if (this.getId() != o.getId()) {
			return 1;
		}

		return 0;
	}

	public void defineBottomLevel() {

		int value = this.getBottomLevel();
		Iterator<Entry<Task, Integer>> iter = this.getSuccessor().entrySet()
				.iterator();

		while (iter.hasNext()) {

			Map.Entry<Task, Integer> entry = (Map.Entry<Task, Integer>) iter
					.next();
			int n = entry.getKey().getBottomLevel();
			int newBottomLevel = n + entry.getValue() + this.getExecutionTime();
			if (newBottomLevel > value) {
				this.setBottomLevel(newBottomLevel);
				value = newBottomLevel;
			}
		}

	}

	/**
	 * 
	 */

	public void defineTopLevel() {

		int value = this.getTopLevel();
		Iterator<Entry<Task, Integer>> iter = this.getPredecessor().entrySet()
				.iterator();
		while (iter.hasNext()) {
			Map.Entry<Task, Integer> entry = (Map.Entry<Task, Integer>) iter
					.next();
			int n = entry.getKey().getTopLevel();
			int newTopLevel = n + entry.getValue()
					+ entry.getKey().getExecutionTime();
			if (newTopLevel > value) {
				this.setTopLevel(newTopLevel);
				value = newTopLevel;
			}
		}
	}

}
